package com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import com.github.pagehelper.PageInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.UserEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.FlowCatalogueService;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowBusi;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.User;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.app.FlowApp;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.app.FlowAppSimpleInfoVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.app.FlowBusiSimpleInfoVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.statistics.CataloguePageable;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.tenant.FlowTenantInfoVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.tenant.FlowTenantQueryVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.tenant.FlowTenantSimpleInfoVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.tenant.FlowUserTenantVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowAppRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowBusiRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowTenantRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowUserTenantRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.UserRepository;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author lilh
 * @date 2020/11/24 下午3:22
 */
@Service
public class FlowCatalogueServiceImpl implements FlowCatalogueService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private FlowUserTenantRepository flowUserTenantRepository;

    @Autowired
    private FlowTenantRepository flowTenantRepository;

    @Autowired
    private FlowAppRepository flowAppRepository;

    @Autowired
    private FlowBusiRepository flowBusiRepository;

    @Override
    public List<FlowTenantSimpleInfoVo> listCatalogue() {
        //1.获取当前用户所属租户
        List<FlowTenantSimpleInfoVo> result = listCurrentUserTenants();
        if (result.isEmpty()) {
            return result;
        }

        //2.根据租户获取租户下所有应用
        List<FlowAppSimpleInfoVo> apps = listCurrentUserApps(result.stream().map(FlowTenantSimpleInfoVo::getId).collect(Collectors.toList()));
        if (apps.isEmpty()) {
            return result;
        }
        Map<Integer, List<FlowAppSimpleInfoVo>> tenantIdToAppsMap = apps.stream().collect(Collectors.groupingBy(FlowAppSimpleInfoVo::getTenantId));

        result.forEach(item -> {
            if (Objects.nonNull(tenantIdToAppsMap.get(item.getId()))) {
                item.setApps(tenantIdToAppsMap.get(item.getId()));
            }
        });

        //2.根据应用获取业务
        List<FlowBusiSimpleInfoVo> busiList = listBusiCatalogue(apps.stream().map(FlowAppSimpleInfoVo::getId).collect(Collectors.toList()));
        if (!busiList.isEmpty()) {
            Map<Integer, List<FlowBusiSimpleInfoVo>> appIdToBusiMap = busiList.stream().collect(Collectors.groupingBy(FlowBusiSimpleInfoVo::getAppId));
            for (FlowAppSimpleInfoVo app : apps) {
                if (Objects.nonNull(appIdToBusiMap.get(app.getId()))) {
                    app.setBusi(appIdToBusiMap.get(app.getId()));
                }
            }
        }

        return result;
    }

    @Override
    public List<FlowTenantSimpleInfoVo> listCurrentUserTenants() {
        User current = userRepository.getCurrentUser();
        if (isSuper(current)) {
            return resolveTenantForSuper();
        }
        //1.获取用户关联的租户
        List<FlowUserTenantVo> userTenants = flowUserTenantRepository.listTenants(current);

        if (CollectionUtils.isEmpty(userTenants)) {
            return Collections.emptyList();
        }
        //2.获取租户基本信息
        return flowTenantRepository.listTenants(userTenants.stream().map(FlowUserTenantVo::getTenantId).collect(Collectors.toList()));
    }

    @Override
    public List<FlowAppSimpleInfoVo> listCurrentUserApps(Integer tenantId) {
        return listCurrentUserApps(Collections.singletonList(tenantId));
    }

    private List<FlowAppSimpleInfoVo> listCurrentUserApps(List<Integer> tenantIds) {
        User current = userRepository.getCurrentUser();
        //1.若是超级管理员，则直接查应用表
        if (isSuper(current)) {
            return resolveAppForSuper(tenantIds);
        }

        //2.若不是超级管理员，则先从关联表中查出应用id,再把应用基本信息查出来
        List<FlowApp> flowApps = flowAppRepository.listApps(tenantIds, current.getUserCode());
        if (CollectionUtils.isEmpty(flowApps)) {
            return Collections.emptyList();
        }
        return flowApps.stream().map(this::convert).collect(Collectors.toList());
    }

    @Override
    public List<FlowBusiSimpleInfoVo> listBusiCatalogue(Integer appId) {
        return listBusiCatalogue(Collections.singletonList(appId));
    }

    @Override
    public boolean checkTenantAuthorize(CataloguePageable cataloguePageable) {
        List<FlowTenantSimpleInfoVo> tenants = this.listCurrentUserTenants();
        if (CollectionUtils.isEmpty(tenants)) {
            logger.warn("当前用户没有权限访问任何租户数据");
            return true;
        }
        List<Integer> tenantIds = tenants.stream().map(FlowTenantSimpleInfoVo::getId).collect(Collectors.toList());
        resolveTenantId(cataloguePageable);
        if (Objects.nonNull(cataloguePageable.getTenantId())) {
            if (!tenantIds.contains(cataloguePageable.getTenantId())) {
                logger.warn("未授权的租户: {}", cataloguePageable.getTenantId());
                return true;
            }
            if (Objects.isNull(cataloguePageable.getAppId())) {
                cataloguePageable.setAppIds(listCurrentUserApps(cataloguePageable.getTenantId()).stream().map(FlowAppSimpleInfoVo::getId).collect(Collectors.toList()));
            }
        } else {
            cataloguePageable.setTenantIds(tenantIds);
            if (Objects.isNull(cataloguePageable.getAppId())) {
                cataloguePageable.setAppIds(listCurrentUserApps(tenantIds).stream().map(FlowAppSimpleInfoVo::getId).collect(Collectors.toList()));
            }
        }
        return false;
    }

    @Override
    public boolean hasAuthorize(Integer tenantId) {
        if (Objects.isNull(tenantId)) {
            logger.warn("未传递租户id,无权访问");
            return false;
        }
        List<FlowTenantSimpleInfoVo> tenants = this.listCurrentUserTenants();
        if (CollectionUtils.isEmpty(tenants)) {
            logger.warn("当前用户没有权限访问任何租户数据");
            return false;
        }
        return tenants.stream().map(FlowTenantSimpleInfoVo::getId).collect(Collectors.toSet()).contains(tenantId);
    }

    private void resolveTenantId(CataloguePageable cataloguePageable) {
        if (Objects.nonNull(cataloguePageable.getTenantId())) {
            return;
        }
        if (Objects.nonNull(cataloguePageable.getAppId())) {
            Integer tenantId = resolveTenantIdByAppId(cataloguePageable.getAppId());
            if (Objects.nonNull(tenantId)) {
                cataloguePageable.setTenantId(tenantId);
            }
        }
    }

    private Integer resolveTenantIdByAppId(Integer appId) {
        FlowApp detail = flowAppRepository.detail(appId);
        if (Objects.nonNull(detail)) {
            return detail.getTenantId();
        }
        return null;
    }

    private List<FlowBusiSimpleInfoVo> listBusiCatalogue(List<Integer> appIds) {
        List<FlowBusi> flowBusiList = flowBusiRepository.list(appIds);
        if (CollectionUtils.isEmpty(flowBusiList)) {
            return Collections.emptyList();
        }

        return flowBusiList.stream().map(item -> {
            FlowBusiSimpleInfoVo tmp = new FlowBusiSimpleInfoVo();
            BeanUtils.copyProperties(item, tmp);
            return tmp;
        }).collect(Collectors.toList());
    }

    private List<FlowAppSimpleInfoVo> resolveAppForSuper(List<Integer> tenantIds) {
        List<FlowApp> flowApps = flowAppRepository.listByTenantIds(tenantIds);
        if (CollectionUtils.isEmpty(flowApps)) {
            return Collections.emptyList();
        }
        return flowApps.stream().map(this::convert).collect(Collectors.toList());
    }

    private List<FlowTenantSimpleInfoVo> resolveTenantForSuper() {
        //直接查询租户表
        FlowTenantQueryVo query = new FlowTenantQueryVo();
        query.setPageSize(100);
        PageInfo<FlowTenantInfoVo> tenants = flowTenantRepository.list(query);
        if (CollectionUtils.isEmpty(tenants.getList())) {
            return Collections.emptyList();
        }
        return tenants.getList().stream().map(item -> {
            FlowTenantSimpleInfoVo tmp = new FlowTenantSimpleInfoVo();
            BeanUtils.copyProperties(item, tmp);
            return tmp;
        }).collect(Collectors.toList());
    }

    private boolean isSuper(User current) {
        return Objects.equals(UserEnum.SUPER.type(), current.getUserType());
    }

    private FlowAppSimpleInfoVo convert(FlowApp flowApp) {
        if (Objects.isNull(flowApp)) {
            return null;
        }

        FlowAppSimpleInfoVo result = new FlowAppSimpleInfoVo();
        BeanUtils.copyProperties(flowApp, result);
        return result;
    }
}
